home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / security / Security.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  24.0 KB  |  785 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)Security.java    1.84 98/10/15
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17. import java.lang.reflect.*;
  18. import java.util.*;
  19. import java.io.*;
  20.  
  21. /**
  22.  * <p>This class centralizes all security properties and common security
  23.  * methods. One of its primary uses is to manage providers.
  24.  *
  25.  * @author Benjamin Renaud
  26.  * @version 1.84, 99/03/26
  27.  */
  28.  
  29. public final class Security {
  30.  
  31.     // Do providers need to be reloaded?
  32.     private static boolean reloadProviders = false;
  33.  
  34.     /* Are we debugging? -- for developers */
  35.     static final boolean debug = false;
  36.  
  37.     /* Are we displaying errors? -- for users */
  38.     static final boolean error = true;
  39.  
  40.     /* The java.security properties */
  41.     private static Properties props; 
  42.  
  43.     /* A vector of providers, in order of priority */
  44.     private static Vector providers;
  45.  
  46.     // Where we cache provider properties
  47.     private static Hashtable providerPropertiesCache;
  48.  
  49.     // Where we cache engine provider properties
  50.     private static Hashtable engineCache;
  51.  
  52.     // An element in the cache
  53.     private static class ProviderProperty {
  54.     String className;
  55.     Provider provider;
  56.     }
  57.  
  58.     static {
  59.     // doPrivileged here because there are multiple
  60.     // things in initialize that might require privs.
  61.     // (the FileInputStream call and the File.exists call,
  62.     // the securityPropFile call, etc)
  63.     AccessController.doPrivileged(new PrivilegedAction() {
  64.         public Object run() { 
  65.         initialize();
  66.         return null;
  67.         }
  68.     });
  69.     }
  70.     
  71.     private static void initialize() {
  72.     props = new Properties();
  73.     providers = new Vector();
  74.     providerPropertiesCache = new Hashtable();
  75.     engineCache = new Hashtable();
  76.  
  77.     File propFile = securityPropFile("java.security");
  78.     if (!propFile.exists()) {
  79.         System.err.println
  80.         ("security properties not found. using defaults.");
  81.         initializeStatic();
  82.     } else {
  83.         try {
  84.         FileInputStream fis = new FileInputStream(propFile);
  85.         InputStream is = new BufferedInputStream(fis);
  86.         props.load(is);
  87.         is.close();
  88.         } catch (IOException e) {
  89.         error("could not load security properties file from " +
  90.               propFile + ". using defaults.");
  91.         initializeStatic();
  92.         }
  93.     }
  94.     loadProviders();
  95.     }
  96.  
  97.     /* 
  98.      * Initialize to default values, if <java.home>/lib/java.security
  99.      * is not found.
  100.      */
  101.     private static void initializeStatic() {
  102.     props.put("security.provider.1", "sun.security.provider.Sun");
  103.     }
  104.  
  105.     /**
  106.      * Don't let anyone instantiate this. 
  107.      */
  108.     private Security() {
  109.     }
  110.  
  111.     /**
  112.      * Loops through provider declarations, which are expected to be
  113.      * of the form:
  114.      *
  115.      * security.provider.1=sun.security.provider.Sun
  116.      * security.provider.2=sun.security.jsafe.Jsafe
  117.      * etc.
  118.      *
  119.      * The order determines the default search order when looking for 
  120.      * an algorithm.
  121.      */
  122.     private static synchronized void loadProviders() {
  123.  
  124.     int i = 1;
  125.     sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  126.  
  127.     while (true) {
  128.         String name = props.getProperty("security.provider." + i++);
  129.         if (name == null) {
  130.         break;
  131.         } else {
  132.         Provider prov = Provider.loadProvider(name);
  133.         if (prov != null) {
  134.             /* This must manipulate the datastructure
  135.                directly, because going through addProviders
  136.                causes a security check to happen, which
  137.                sometimes will cause the security
  138.                initialization to fail with bad
  139.                consequences. */
  140.             providers.addElement(prov);
  141.         } else if (l == null) {
  142.             reloadProviders = true;
  143.         }
  144.         }
  145.     }
  146.     }
  147.  
  148.     /*
  149.      * Reload the providers (provided as extensions) that could not be loaded 
  150.      * (because there was no system class loader available).when this class
  151.      * was initialized.
  152.      */
  153.     private static synchronized void reloadProviders() {
  154.     if (reloadProviders) {
  155.         sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
  156.         if (l != null) {
  157.         reloadProviders = false;
  158.         providers.removeAllElements();
  159.         int i = 1;
  160.         while (true) {
  161.             final String name =
  162.             props.getProperty("security.provider." + i++);
  163.             if (name == null) {
  164.             break;
  165.             } else {
  166.             Provider prov =
  167.                 (Provider)AccessController.doPrivileged(
  168.                                new PrivilegedAction() {
  169.                 public Object run() { 
  170.                     return Provider.loadProvider(name);
  171.                 }
  172.                 });
  173.             if (prov != null) {
  174.                 providers.addElement(prov);
  175.             }
  176.             }
  177.         }
  178.         // empty provider-property cache
  179.         providerPropertiesCache.clear();
  180.         engineCache.clear();
  181.         }
  182.     }
  183.     }
  184.  
  185.     private static File securityPropFile(String filename) {
  186.     // maybe check for a system property which will specify where to
  187.     // look. Someday.
  188.     String sep = File.separator;
  189.     return new File(System.getProperty("java.home") + sep + "lib" + sep + 
  190.             "security" + sep + filename);
  191.     }
  192.  
  193.     /**
  194.      * Looks up providers, and returns the property (and its associated
  195.      * provider) mapping the key, if any.
  196.      * The order in which the providers are looked up is the
  197.      * provider-preference order, as specificed in the security
  198.      * properties file.
  199.      */
  200.     private static ProviderProperty getProviderProperty(String key) {
  201.     ProviderProperty entry
  202.         = (ProviderProperty)providerPropertiesCache.get(key);
  203.     if (entry != null) {
  204.         return entry;
  205.     }
  206.  
  207.     for (int i = 0; i < providers.size(); i++) {
  208.  
  209.         String matchKey = null;
  210.         Provider prov = (Provider)providers.elementAt(i);        
  211.         String prop = prov.getProperty(key);
  212.  
  213.         if (prop == null) {
  214.         // Is there a match if we do a case-insensitive property name
  215.         // comparison? Let's try ...
  216.         for (Enumeration enum = prov.keys();
  217.              enum.hasMoreElements() && prop==null; ) {
  218.             matchKey = (String)enum.nextElement();
  219.             if (key.equalsIgnoreCase(matchKey)) {
  220.             prop = prov.getProperty(matchKey);
  221.             break;
  222.             }
  223.         }
  224.         }
  225.  
  226.         if (prop != null) {
  227.         ProviderProperty newEntry = new ProviderProperty();
  228.         newEntry.className = prop;
  229.         newEntry.provider = prov;
  230.         providerPropertiesCache.put(key, newEntry);
  231.         if (matchKey != null) {
  232.             // Store the property value in the cache under the exact
  233.             // property name, as specified by the provider
  234.             providerPropertiesCache.put(matchKey, newEntry);
  235.         }
  236.         return newEntry;
  237.         }
  238.     }
  239.  
  240.     return entry;
  241.     }
  242.  
  243.     /**
  244.      * Returns the property (if any) mapping the key for the given provider.
  245.      */
  246.     private static String getProviderProperty(String key, Provider provider) {
  247.     String prop = provider.getProperty(key);
  248.     if (prop == null) {
  249.         // Is there a match if we do a case-insensitive property name
  250.         // comparison? Let's try ...
  251.         for (Enumeration enum = provider.keys();
  252.          enum.hasMoreElements() && prop==null; ) {
  253.         String matchKey = (String)enum.nextElement();
  254.         if (key.equalsIgnoreCase(matchKey)) {
  255.             prop = provider.getProperty(matchKey);
  256.             break;
  257.         }
  258.         }
  259.     }
  260.     return prop;
  261.     }
  262.  
  263.     /**
  264.      * We always map names to standard names
  265.      */
  266.     private static String getStandardName(String alias, String engineType,
  267.         Provider prov) {
  268.     return getProviderProperty("Alg.Alias." + engineType + "." + alias,
  269.                    prov);
  270.     }
  271.  
  272.     /** 
  273.      * Gets a specified property for an algorithm. The algorithm name
  274.      * should be a standard name. See Appendix A in the <a href=
  275.      * "../../../guide/security/CryptoSpec.html#AppA">
  276.      * Java Cryptography Architecture API Specification & Reference </a> 
  277.      * for information about standard algorithm names.
  278.      * One possible use is by specialized algorithm parsers, which may map 
  279.      * classes to algorithms which they understand (much like Key parsers 
  280.      * do).
  281.      *
  282.      * @param algName the algorithm name.
  283.      *
  284.      * @param propName the name of the property to get.
  285.      * 
  286.      * @return the value of the specified property.  
  287.      *
  288.      * @deprecated This method used to return the value of a proprietary
  289.      * property in the master file of the "SUN" Cryptographic Service
  290.      * Provider in order to determine how to parse algorithm-specific
  291.      * parameters. Use the new provider-based and algorithm-independent
  292.      * <code>AlgorithmParameters</code> and <code>KeyFactory</code> engine
  293.      * classes (introduced in JDK 1.2) instead.
  294.      */
  295.     public static String getAlgorithmProperty(String algName,
  296.                           String propName) {
  297.     reloadProviders();
  298.     ProviderProperty entry = getProviderProperty("Alg." + propName
  299.                              + "." + algName);
  300.     if (entry != null) {
  301.         return entry.className;
  302.     } else {
  303.         return null;
  304.     }
  305.     }
  306.  
  307.     /*
  308.      * Lookup the algorithm in our list of providers. Process
  309.      * each provider in priority order one at a time looking for
  310.      * either the direct engine property or a matching alias.
  311.      */
  312.     private static ProviderProperty getEngineClassName(String algName,
  313.                                String engineType)
  314.         throws NoSuchAlgorithmException
  315.     {
  316.     ProviderProperty pp;
  317.     String key = engineType;
  318.  
  319.     if (algName != null)
  320.         key += "." + algName;
  321.     pp = (ProviderProperty)engineCache.get(key);
  322.     if (pp != null)
  323.         return pp;
  324.  
  325.         for (int i = 0; i < providers.size(); i++) {
  326.             Provider prov = (Provider)providers.elementAt(i);
  327.         try {
  328.         pp = getEngineClassName(algName, prov.getName(), engineType);
  329.         } catch (NoSuchAlgorithmException e) {
  330.         continue;
  331.         } catch (NoSuchProviderException e) {
  332.         // can't happen except for sync failures
  333.         continue;
  334.         }
  335.  
  336.         /* Cache it */
  337.         engineCache.put(key, pp);
  338.         return pp;
  339.     }
  340.  
  341.     throw new NoSuchAlgorithmException(engineType + " not available");
  342.     }
  343.  
  344.  
  345.     private static ProviderProperty getEngineClassName(String algName,
  346.                                String provider, 
  347.                                String engineType) 
  348.     throws NoSuchAlgorithmException, NoSuchProviderException
  349.     {
  350.     if (provider == null) {
  351.         return getEngineClassName(algName, engineType);
  352.     }
  353.  
  354.     // check if the provider is installed
  355.     Provider prov = getProvider(provider);
  356.     if (prov == null) {
  357.         throw new NoSuchProviderException("no such provider: " +
  358.                           provider);
  359.     }
  360.  
  361.     String key;
  362.     if (engineType.equalsIgnoreCase("SecureRandom") && algName == null)
  363.         key = engineType;
  364.     else
  365.         key = engineType + "." + algName;
  366.     
  367.     String className = getProviderProperty(key, prov);
  368.     if (className == null) {
  369.         if (engineType.equalsIgnoreCase("SecureRandom") &&
  370.         algName == null)
  371.         throw new NoSuchAlgorithmException
  372.             ("SecureRandom not available for provider " + provider);
  373.         else {
  374.         // try algName as alias name
  375.         String stdName = getStandardName(algName, engineType, prov);
  376.         if (stdName != null) key = engineType + "." + stdName;
  377.         if ((stdName == null)
  378.             || (className = getProviderProperty(key, prov)) == null)
  379.             throw new NoSuchAlgorithmException("no such algorithm: " +
  380.                                algName
  381.                                + " for provider " +
  382.                                provider);
  383.         }
  384.     }
  385.     
  386.     ProviderProperty entry = new ProviderProperty();
  387.     entry.className = className;
  388.     entry.provider = prov;
  389.  
  390.     return entry;
  391.     }
  392.  
  393.     /**
  394.      * Adds a new provider, at a specified position. The position is
  395.      * the preference order in which providers are searched for
  396.      * requested algorithms. Note that it is not guaranteed that this
  397.      * preference will be respected. The position is 1-based, that is,
  398.      * 1 is most preferred, followed by 2, and so on. Sometimes it
  399.      * will be legal to add a provider, but only in the last position,
  400.      * in which case the <code>position</code> argument will be ignored. 
  401.      * 
  402.      * <p>If the given provider is installed at the requested position,
  403.      * the provider that used to be at that position, and all providers
  404.      * with a position greater than <code>position</code>, are shifted up
  405.      * one position (towards the end of the list of installed providers).
  406.      * 
  407.      * <p>A provider cannot be added if it is already installed.
  408.      * 
  409.      * <p>First, if there is a security manager, its
  410.      * <code>checkSecurityAccess</code> 
  411.      * method is called with the string
  412.      * <code>"insertProvider."+provider.getName()</code> 
  413.      * to see if it's ok to add a new provider. 
  414.      * If the default implementation of <code>checkSecurityAccess</code> 
  415.      * is used (i.e., that method is not overriden), then this will result in
  416.      * a call to the security manager's <code>checkPermission</code> method
  417.      * with a
  418.      * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  419.      * permission.
  420.      *
  421.      * @param provider the provider to be added.
  422.      *
  423.      * @param position the preference position that the caller would
  424.      * like for this provider.
  425.      * 
  426.      * @return the actual preference position in which the provider was 
  427.      * added, or -1 if the provider was not added because it is
  428.      * already installed.
  429.      *
  430.      * @throws  SecurityException
  431.      *          if a security manager exists and its <code>{@link
  432.      *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  433.      *          denies access to add a new provider
  434.      *
  435.      * @see #getProvider
  436.      * @see #removeProvider 
  437.      * @see java.security.SecurityPermission
  438.      */
  439.     public static int insertProviderAt(Provider provider, int position) {
  440.     reloadProviders();
  441.  
  442.     check("insertProvider."+provider.getName());
  443.  
  444.     /* First check if the provider is already installed */
  445.     Provider already = getProvider(provider.getName());
  446.     if (already != null) {
  447.         return -1;
  448.     }    
  449.         
  450.     int size = providers.size();
  451.     if (position > size || position <= 0) {
  452.         position = size+1;
  453.     }
  454.  
  455.     providers.insertElementAt(provider, position-1);
  456.  
  457.     // empty provider-property cache
  458.     providerPropertiesCache.clear();
  459.     engineCache.clear();
  460.     
  461.     return position;
  462.     }
  463.  
  464.     /**
  465.      * Adds a provider to the next position available.
  466.      *
  467.      * <p>First, if there is a security manager, its
  468.      * <code>checkSecurityAccess</code> 
  469.      * method is called with the string
  470.      * <code>"insertProvider."+provider.getName()</code> 
  471.      * to see if it's ok to add a new provider. 
  472.      * If the default implementation of <code>checkSecurityAccess</code> 
  473.      * is used (i.e., that method is not overriden), then this will result in
  474.      * a call to the security manager's <code>checkPermission</code> method
  475.      * with a
  476.      * <code>SecurityPermission("insertProvider."+provider.getName())</code>
  477.      * permission.
  478.      * 
  479.      * @param provider the provider to be added.
  480.      *
  481.      * @return the preference position in which the provider was 
  482.      * added, or -1 if the provider was not added because it is
  483.      * already installed.
  484.      *
  485.      * @throws  SecurityException
  486.      *          if a security manager exists and its <code>{@link
  487.      *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  488.      *          denies access to add a new provider
  489.      * 
  490.      * @see #getProvider
  491.      * @see #removeProvider
  492.      * @see java.security.SecurityPermission
  493.      */
  494.     public static int addProvider(Provider provider) {
  495.     return insertProviderAt(provider, providers.size() + 1);
  496.     }
  497.  
  498.     /**
  499.      * Removes the provider with the specified name.
  500.      *
  501.      * <p>When the specified provider is removed, all providers located
  502.      * at a position greater than where the specified provider was are shifted
  503.      * down one position (towards the head of the list of installed
  504.      * providers).
  505.      *
  506.      * <p>This method returns silently if the provider is not installed.
  507.      * 
  508.      * <p>First, if there is a security manager, its
  509.      * <code>checkSecurityAccess</code> 
  510.      * method is called with the string <code>"removeProvider."+name</code> 
  511.      * to see if it's ok to remove the provider. 
  512.      * If the default implementation of <code>checkSecurityAccess</code> 
  513.      * is used (i.e., that method is not overriden), then this will result in
  514.      * a call to the security manager's <code>checkPermission</code> method
  515.      * with a <code>SecurityPermission("removeProvider."+name)</code>
  516.      * permission.
  517.      *
  518.      * @param name the name of the provider to remove.
  519.      *
  520.      * @throws  SecurityException
  521.      *          if a security manager exists and its <code>{@link
  522.      *          java.lang.SecurityManager#checkSecurityAccess}</code> method
  523.      *          denies
  524.      *          access to remove the provider
  525.      *
  526.      * @see #getProvider
  527.      * @see #addProvider
  528.      */
  529.     public static void removeProvider(String name) {
  530.     reloadProviders();
  531.     check("removeProvider."+name);
  532.     Provider provider = getProvider(name);
  533.     if (provider != null) {
  534.         providers.removeElement(provider);
  535.  
  536.         // empty provider-property cache
  537.         providerPropertiesCache.clear();
  538.         engineCache.clear();
  539.     }
  540.     }
  541.     
  542.     /**
  543.      * Returns an array containing all the installed providers. The order of
  544.      * the providers in the array is their preference order.
  545.      * 
  546.      * @return an array of all the installed providers.
  547.      */
  548.     public static Provider[] getProviders() {
  549.     reloadProviders();
  550.     Provider[] result = new Provider[providers.size()];
  551.     providers.copyInto(result);
  552.     return result;
  553.     }
  554.  
  555.     /**
  556.      * Returns the provider installed with the specified name, if
  557.      * any. Returns null if no provider with the speicified name is
  558.      * installed.
  559.      * 
  560.      * @param name the name of the provider to get.
  561.      * 
  562.      * @return the provider of the specified name.
  563.      *
  564.      * @see #removeProvider
  565.      * @see #addProvider
  566.      */
  567.     public static Provider getProvider(String name) {
  568.     // Search through the list of already loaded providers
  569.     Enumeration enum = providers.elements();
  570.     while (enum.hasMoreElements()) {
  571.         Provider prov = (Provider)enum.nextElement();
  572.         if (prov.getName().equals(name)) {
  573.         return prov;
  574.         }
  575.     }
  576.     // See if the requested provider is among the providers that need
  577.     // to be reloaded
  578.     if (reloadProviders) {
  579.         int provsSize = providers.size();
  580.         reloadProviders();
  581.         if (providers.size() > provsSize) {
  582.         enum = providers.elements();
  583.         while (enum.hasMoreElements()) {
  584.             Provider prov = (Provider)enum.nextElement();
  585.             if (prov.getName().equals(name)) {
  586.             return prov;
  587.             }
  588.         }
  589.         }
  590.     }
  591.  
  592.     return null;
  593.     }
  594.  
  595.     private static boolean checkSuperclass(Class subclass, Class superclass) {
  596.     while(!subclass.equals(superclass)) {
  597.         subclass = subclass.getSuperclass();
  598.         if (subclass == null) {
  599.         return false;
  600.         }
  601.     }
  602.     return true;
  603.     }
  604.  
  605.     /*
  606.      * Returns an array of objects: the first object in the array is
  607.      * an instance of an implementation of the requested algorithm
  608.      * and type, and the second object in the array identifies the provider
  609.      * of that implementation.
  610.      * The <code>provider</code> argument can be null, in which case all
  611.      * configured providers will be searched in order of preference.
  612.      */
  613.     static Object[] getImpl(String algorithm, String type, String provider)
  614.     throws NoSuchAlgorithmException, NoSuchProviderException
  615.     {
  616.     reloadProviders();
  617.  
  618.     ProviderProperty pp = getEngineClassName(algorithm, provider, type);
  619.     String className = pp.className;
  620.  
  621.     try {
  622.         // java.security.<type>.Spi is a system class, therefore
  623.         // Class.forName() always works
  624.         Class typeClass;
  625.         if (type.equals("CertificateFactory")) {
  626.         typeClass = Class.forName("java.security.cert." + type
  627.                       + "Spi");
  628.         } else {
  629.         typeClass = Class.forName("java.security." + type + "Spi");
  630.         }
  631.  
  632.         // Load the implementation class using the same class loader that
  633.         // was used to load the associated provider.
  634.         // In order to get the class loader of a class, the caller's class
  635.         // loader must be the same as or an ancestor of the class loader
  636.         // being returned.
  637.         // Since java.security.Security is a system class, it can get the
  638.         // class loader of any class (the system class loader is an
  639.         // ancestor of all class loaders).
  640.         ClassLoader cl = pp.provider.getClass().getClassLoader();
  641.         Class implClass;
  642.         if (cl != null) {
  643.         implClass = cl.loadClass(className);
  644.         } else {
  645.         implClass = Class.forName(className);
  646.         }
  647.  
  648.         if (checkSuperclass(implClass, typeClass)) {
  649.         Object obj = implClass.newInstance();
  650.         return new Object[] { obj, pp.provider };
  651.         } else {
  652.         throw new NoSuchAlgorithmException("class configured for " + 
  653.                            type + ": " + className + 
  654.                            " not a " + type);
  655.         }
  656.     } catch (ClassNotFoundException e) {
  657.         throw new NoSuchAlgorithmException("class configured for " + 
  658.                            type + "(provider: " + 
  659.                            provider + ")" + 
  660.                            "cannot be found.\n" + 
  661.                            e.getMessage());
  662.     } catch (InstantiationException e) {
  663.         throw new NoSuchAlgorithmException("class " + className + 
  664.                            " configured for " + type +
  665.                            "(provider: " + provider + 
  666.                            ") cannot be instantiated.\n"+ 
  667.                            e.getMessage());
  668.     } catch (IllegalAccessException e) {
  669.         throw new NoSuchAlgorithmException("class " + className + 
  670.                            " configured for " + type +
  671.                            "(provider: " + provider +
  672.                            ") cannot be accessed.\n" + 
  673.                            e.getMessage());
  674.     } catch (SecurityException e) {
  675.         throw new NoSuchAlgorithmException("class " + className + 
  676.                            " configured for " + type +
  677.                            "(provider: " + provider +
  678.                            ") cannot be accessed.\n" + 
  679.                            e.getMessage());
  680.     }
  681.     }
  682.  
  683.     /**
  684.      * Gets a security property value.
  685.      *
  686.      * <p>First, if there is a security manager, its
  687.      * <code>checkPermission</code>  method is called with a 
  688.      * <code>java.security.SecurityPermission("getProperty."+key)</code>
  689.      * permission to see if it's ok to retrieve the specified
  690.      * security property value.. 
  691.      *
  692.      * @param key the key of the property being retrieved.
  693.      *
  694.      * @return the value of the security property corresponding to key.
  695.      *
  696.      * @throws  SecurityException
  697.      *          if a security manager exists and its <code>{@link
  698.      *          java.lang.SecurityManager#checkPermission}</code> method
  699.      *          denies
  700.      *          access to retrieve the specified security property value
  701.      * 
  702.      * @see java.security.SecurityPermission
  703.      */
  704.     public static String getProperty(String key) {
  705.     SecurityManager sm = System.getSecurityManager();
  706.     if (sm != null) {
  707.         sm.checkPermission(new SecurityPermission("getProperty."+
  708.                               key));
  709.     }
  710.     return props.getProperty(key);
  711.     }
  712.  
  713.     /**
  714.      * Sets a security property value.
  715.      *
  716.      * <p>First, if there is a security manager, its
  717.      * <code>checkPermission</code> method is called with a 
  718.      * <code>java.security.SecurityPermission("setProperty."+key)</code>
  719.      * permission to see if it's ok to set the specified
  720.      * security property value.
  721.      *
  722.      * @param key the name of the property to be set.
  723.      *
  724.      * @param datum the value of the property to be set.
  725.      *
  726.      * @throws  SecurityException
  727.      *          if a security manager exists and its <code>{@link
  728.      *          java.lang.SecurityManager#checkPermission}</code> method
  729.      *          denies access to set the specified security property value
  730.      * 
  731.      * @see java.security.SecurityPermission
  732.      */
  733.     public static void setProperty(String key, String datum) {
  734.     check("setProperty."+key);
  735.     props.put(key, datum);
  736.     }
  737.  
  738.     private static void check(String directive) {    
  739.     SecurityManager security = System.getSecurityManager();
  740.     if (security != null) {
  741.         security.checkSecurityAccess(directive);
  742.     }
  743.     }
  744.     
  745.     /**
  746.      * Print an error message that may be significant to a user.
  747.      */
  748.     static void error(String msg) {
  749.     if (debug) {
  750.         System.err.println(msg);
  751.     }
  752.     }
  753.  
  754.     /**
  755.      * Print an error message that may be significant to a user.
  756.      */
  757.     static void error(String msg, Throwable t) {
  758.     error(msg);
  759.     if (debug) {
  760.         t.printStackTrace();
  761.     }
  762.     }
  763.     
  764.     /**
  765.      * Print an debugging message that may be significant to a developer.
  766.      */
  767.     static void debug(String msg) {
  768.     if (debug) {
  769.         System.err.println(msg);
  770.     }
  771.     }
  772.  
  773.     /**
  774.      * Print an debugging message that may be significant to a developer.
  775.      */
  776.     static void debug(String msg, Throwable t) {
  777.     if (debug) {
  778.         t.printStackTrace();
  779.         System.err.println(msg);
  780.     }
  781.     }
  782. }
  783.     
  784.  
  785.